1 # -*- coding: utf-8 -*-
2 ##############################################################################
4 # POS Membership module for OpenERP, Manage membership payments from POS.
5 # Copyright (C) 2013 L'Heureux Cyclage (<http://www.heureux-cyclage.org>)
7 # This file is a part of POS Membership
9 # POS Membership is free software: you can redistribute it and/or modify
10 # it under the terms of the GNU General Public License as published by
11 # the Free Software Foundation, either version 3 of the License, or
12 # (at your option) any later version.
14 # POS Membership is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 # GNU General Public License for more details.
19 # You should have received a copy of the GNU General Public License
20 # along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ##############################################################################
23 from openerp
import netsvc
24 from openerp
.osv
import fields
, osv
25 from openerp
.tools
.translate
import _
27 from datetime
import datetime
, date
28 from dateutil
.relativedelta
import relativedelta
32 ('none', 'Non Member'),
33 ('canceled', 'Cancelled Member'),
34 ('old', 'Old Member'),
35 ('waiting', 'Waiting Member'),
36 ('invoiced', 'Invoiced Member'),
37 ('free', 'Free Member'),
38 ('paid', 'Paid Member'),
42 class pos_session(osv
.osv
):
43 _inherit
= 'pos.session'
45 def open_cb(self
, cr
, uid
, ids
, context
=None):
47 Avoid call the Point Of Sale interface and set the pos.session to 'opened' (in progress)
52 if isinstance(ids
, (int, long)):
55 this_record
= self
.browse(cr
, uid
, ids
[0], context
=context
)
56 this_record
._workflow
_signal
('open')
58 context
.update(active_id
=this_record
.id)
66 class pos_order(osv
.osv
):
67 _inherit
= 'pos.order'
69 def create_partner_from_ui(self
, cr
, uid
, partners
, context
=None):
70 print ("DEV: [pos_membership] [create_partner_from_ui] partners=%s" % str(partners
))
72 partner_obj
= self
.pool
.get('res.partner')
73 for tmp_partner
in partners
:
74 partner
= tmp_partner
['data']
75 partner_id
= partner_obj
.create(cr
, uid
, {
76 'name': partner
['name'],
78 partner_ids
.append(partner_id
)
79 #self.signal_paid(cr, uid, [partner_id])
82 def create_from_ui(self
, cr
, uid
, orders
, context
=None):
83 # NOTE: copied from openerp/addons/point_of_sale/point_of_sale.py
84 #_logger.info("orders: %r", orders)
85 print ("DEV: [pos_membership] [create_from_ui] order=", str(orders
))
87 for tmp_order
in orders
:
88 order
= tmp_order
['data']
89 order_id
= self
.create(cr
, uid
, {
90 'name': order
['name'],
91 'user_id': order
['user_id'] or False,
92 'session_id': order
['pos_session_id'],
93 'lines': order
['lines'],
94 'pos_reference': order
['name'],
95 #-- BEGIN pos_membership
96 'partner_id': order
['partner_id'],
97 #-- END pos_membership
100 for payments
in order
['statement_ids']:
101 payment
= payments
[2]
102 self
.add_payment(cr
, uid
, order_id
, {
103 'amount': payment
['amount'] or 0.0,
104 'payment_date': payment
['name'],
105 'statement_id': payment
['statement_id'],
106 'payment_name': payment
.get('note', False),
107 'journal': payment
['journal_id']
110 if order
['amount_return']:
111 session
= self
.pool
.get('pos.session').browse(cr
, uid
, order
['pos_session_id'], context
=context
)
112 cash_journal
= session
.cash_journal_id
113 cash_statement
= False
115 cash_journal_ids
= filter(lambda st
: st
.journal_id
.type == 'cash', session
.statement_ids
)
116 if not len(cash_journal_ids
):
117 raise osv
.except_osv(_('error!'),
118 _("No cash statement found for this session. Unable to record returned cash."))
119 cash_journal
= cash_journal_ids
[0].journal_id
120 self
.add_payment(cr
, uid
, order_id
, {
121 'amount': -order
['amount_return'],
122 'payment_date': time
.strftime('%Y-%m-%d %H:%M:%S'),
123 'payment_name': _('return'),
124 'journal': cash_journal
.id,
126 order_ids
.append(order_id
)
127 wf_service
= netsvc
.LocalService("workflow")
128 wf_service
.trg_validate(uid
, 'pos.order', order_id
, 'paid', cr
)
134 class membership_line(osv
.osv
):
136 _inherit
= 'membership.membership_line'
138 def _get_partners(self
, cr
, uid
, ids
, context
=None):
139 list_membership_line
= []
140 member_line_obj
= self
.pool
.get('membership.membership_line')
141 for partner
in self
.pool
.get('res.partner').browse(cr
, uid
, ids
, context
=context
):
142 if partner
.member_lines
:
143 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('id', 'in', [l
.id for l
in partner
.member_lines
])], context
=context
)
144 print("DEV: [pos_membership] [membership_line] [_get_partners]: ids=%s res=%s" % (str(ids
), str(list_membership_line
)))
145 return list_membership_line
147 #def _get_membership_lines_from_account_invoice(self, cr, uid, ids, context=None):
148 # list_membership_line = []
149 # member_line_obj = self.pool.get('membership.membership_line')
150 # for invoice in self.pool.get('account.invoice').browse(cr, uid, ids, context=context):
151 # if invoice.invoice_line:
152 # list_membership_line += member_line_obj.search(cr, uid, [('account_invoice_line', 'in', [ l.id for l in invoice.invoice_line])], context=context)
154 # { 'class': 'account.invoice'
155 # , 'ids': list_membership_line
157 # #res= list_membership_line
158 # print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_account_invoice]: res=%s" % str(res))
160 def _get_membership_lines_from_pos_order(self
, cr
, uid
, ids
, context
=None):
161 list_membership_line
= []
162 member_line_obj
= self
.pool
.get('membership.membership_line')
163 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: ids=%s context=%s" % (str(ids
), str(context
)))
164 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
166 list_membership_line
+= member_line_obj
.search(cr
, uid
, [('pos_order_line', 'in', [l
.id for l
in order
.lines
])], context
=context
)
168 # { 'class': 'pos.order'
169 # , 'ids': list_membership_line
171 res
= list_membership_line
172 print("DEV: [pos_membership] [membership_line] [_get_membership_lines_from_pos_order]: res=%s" % str(res
))
175 def _check_membership_date(self
, cr
, uid
, ids
, context
=None):
176 """Check if membership product is not in the past
177 @param self: The object pointer
178 @param cr: the current row, from the database cursor,
179 @param uid: the current user’s ID for security checks,
180 @param ids: List of Membership Line IDs
181 @param context: A standard dictionary for contextual values
185 SELECT MIN(ml.date_to - ai.date_invoice)
186 FROM membership_membership_line ml
187 JOIN account_invoice_line ail ON (
188 ml.account_invoice_line = ail.id
190 JOIN account_invoice ai ON (
191 ai.id = ail.invoice_id)
192 WHERE ml.id IN %s''', (tuple(ids
),))
195 if r
[0] and r
[0] < 0:
198 SELECT MIN(ml.date_to - ai.date_order)
199 FROM membership_membership_line ml
200 JOIN pos_order_line ail ON (
201 ml.pos_order_line = ail.id
203 JOIN pos_order ai ON (
204 ai.id = ail.order_id)
205 WHERE ml.id IN %s''', (tuple(ids
),))
208 if r
[0] and r
[0] < 0:
212 def _state(self
, cr
, uid
, ids
, name
, args
, context
=None):
213 """Compute the state lines
214 @param self: The object pointer
215 @param cr: the current row, from the database cursor,
216 @param uid: the current user’s ID for security checks,
217 @param ids: List of Membership Line IDs
218 @param name: Field Name
219 @param context: A standard dictionary for contextual values
220 @param return: Dictionary of state Value
223 print("DEV: [pos_membership] [membership_line] [_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
224 inv_obj
= self
.pool
.get('account.invoice')
225 ord_obj
= self
.pool
.get('pos.order')
226 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
228 SELECT i.state, i.id FROM
232 SELECT l.invoice_id FROM
233 account_invoice_line l WHERE
235 SELECT ml.account_invoice_line FROM
236 membership_membership_line ml WHERE
241 fetched
= cr
.fetchone()
245 if (istate
== 'draft') |
(istate
== 'proforma'):
247 elif istate
== 'open':
249 elif istate
== 'paid':
251 inv
= inv_obj
.browse(cr
, uid
, fetched
[1], context
=context
)
252 for payment
in inv
.payment_ids
:
253 if payment
.invoice
and payment
.invoice
.type == 'out_refund':
255 elif istate
== 'cancel':
260 SELECT i.state, i.id FROM
264 SELECT l.order_id FROM
265 pos_order_line l WHERE
267 SELECT ml.pos_order_line FROM
268 membership_membership_line ml WHERE
273 fetched
= cr
.fetchone()
275 res
[line
.id] = 'canceled'
277 print("DEV: [pos_membership] [membership_line] [_state]: line.partner.id=%s" % (str(line
.partner
.id)))
278 self
.write(cr
, uid
, line
.id, {'partner': line
.partner
.id})
279 # NOTE: force une mise à jour du partner,
280 # car il n'y en a pas lors de la création du pos.order
281 # dans le PoS (pour le moment)
282 partner_obj
= self
.pool
.get('res.partner')
283 for partner
in partner_obj
.browse(cr
, uid
, [line
.partner
.id], context
=context
):
284 if not partner
.member_ident
:
285 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
286 partner_obj
.write(cr
, uid
, partner
.id, {'member_ident': mbr_id
})
289 if (ostate
== 'paid') |
(ostate
== 'draft'):
291 elif (ostate
== 'done') |
(ostate
== 'invoiced'):
293 # XXX: regarder l'équivalent de out_refund pour un pos.order
294 print("DEV: [pos_membership] [membership_line] [_state]: paid: TODO")
295 #inv = ord_obj.browse(cr, uid, fetched[1], context=context)
296 #for payment in inv.payment_ids:
297 # if payment.invoice and payment.invoice.type == 'out_refund':
299 elif ostate
== 'cancel':
302 print("DEV: [pos_membership] [membership_line] [_state]: return=%s" % (str(res
)))
305 def write(self
, cr
, uid
, ids
, vals
, context
=None):
306 print("DEV: [pos_membership] [membership_line] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
307 res
= super(membership_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
308 print("DEV: [pos_membership] [membership_line] [write]: res=%s" % str(res
))
311 def create(self
, cr
, uid
, vals
, context
=None):
312 print("DEV: [pos_membership] [membership_line] [create]: vals=%s" % (str(vals
)))
313 member_line_obj
= self
.pool
.get('membership.membership_line')
314 res
= super(membership_line
, self
).create(cr
, uid
, vals
, context
=context
)
315 print("DEV: [pos_membership] [membership_line] [create]: res=%s" % (str(res
)))
319 'pos_order_line': fields
.many2one('pos.order.line', 'POS Order line', readonly
=True),
320 'pos_order_id': fields
.related('pos_order_line', 'order_id', type='many2one', relation
='pos.order', string
='Order', readonly
=True),
321 'state': fields
.function(_state
,
322 string
='Membership Status', type='selection',
325 #'account.invoice': (_get_membership_lines_from_account_invoice, ['state'], 10),
326 # NOTE: déjà géré par membership.membership_line._get_membership_lines
327 'pos.order': (_get_membership_lines_from_pos_order
, ['state', 'partner_id'], 10),
328 'res.partner': (_get_partners
, ['membership_state'], 12),
329 }, help="""It indicates the membership status.
330 -Non Member: A member who has not applied for any membership.
331 -Cancelled Member: A member who has cancelled his membership.
332 -Old Member: A member whose membership date has expired.
333 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
334 -Invoiced Member: A member whose invoice has been created.
335 -Paid Member: A member who has paid the membership amount."""),
336 'company_id': fields
.related('account_invoice_line', 'invoice_id', 'company_id', type="many2one", relation
="res.company", string
="Company", readonly
=True, store
=True)
337 # XXX: pos_order_line a aussi un company_id
343 class Partner(osv
.osv
):
345 _inherit
= 'res.partner'
347 def _get_partner_id(self
, cr
, uid
, ids
, context
=None):
348 print("DEV: [pos_membership] [Partner] [_get_partner_id]: ids=%s context=%s" % (str(ids
), str(context
)))
349 member_line_obj
= self
.pool
.get('membership.membership_line')
350 res_obj
= self
.pool
.get('res.partner')
351 data_inv
= member_line_obj
.browse(cr
, uid
, ids
, context
=context
)
353 for data
in data_inv
:
354 list_partner
.append(data
.partner
.id)
357 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
359 print("DEV: [pos_membership] [Partner] [_get_partner_id]: res=%s" % (str(list_partner
)))
362 def _get_invoice_partner(self
, cr
, uid
, ids
, context
=None):
363 inv_obj
= self
.pool
.get('account.invoice')
364 res_obj
= self
.pool
.get('res.partner')
365 data_inv
= inv_obj
.browse(cr
, uid
, ids
, context
=context
)
367 for data
in data_inv
:
368 list_partner
.append(data
.partner_id
.id)
371 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
375 def _get_order_partner(self
, cr
, uid
, ids
, context
=None):
376 ord_obj
= self
.pool
.get('pos.order')
377 res_obj
= self
.pool
.get('res.partner')
378 data_ord
= ord_obj
.browse(cr
, uid
, ids
, context
=context
)
380 for data
in data_ord
:
381 list_partner
.append(data
.partner_id
.id)
384 ids2
= res_obj
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
388 def _membership_state(self
, cr
, uid
, ids
, name
, args
, context
=None):
389 """This Function return Membership State For Given Partner.
390 @param self: The object pointer
391 @param cr: the current row, from the database cursor,
392 @param uid: the current user’s ID for security checks,
393 @param ids: List of Partner IDs
394 @param name: Field Name
395 @param context: A standard dictionary for contextual values
396 @param return: Dictionary of Membership state Value
399 print("DEV: [pos_membership] [Partner] [_membership_state]: name=%s ids=%s args=%s context=%s" % (str(name
), str(ids
), str(args
), str(context
)))
402 today
= time
.strftime('%Y-%m-%d')
404 print("DEV: [pos_membership] [Partner] [_membership_state] id=%s" % (str(id)))
405 partner_data
= self
.browse(cr
, uid
, id, context
=context
)
406 if partner_data
.membership_cancel
and today
> partner_data
.membership_cancel
:
409 if partner_data
.membership_stop
and today
> partner_data
.membership_stop
:
413 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines] [test]")
414 if partner_data
.member_lines
:
415 print("DEV: [pos_membership] [Partner] [_membership_state] [partner_data] [member_lines]" % ())
416 for mline
in partner_data
.member_lines
:
417 print("DEV: [pos_membership] [Partner] [_membership_state] [mline]: id=%s" % str(mline
.id))
418 if mline
.date_to
>= today
:
419 if mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
:
420 istate
= mline
.account_invoice_line
.invoice_id
.state
421 print("DEV: [pos_membership] [Partner] [_membership_state] [account_invoice_line]: id=%s istate=%s" % (str(mline
.account_invoice_line
.invoice_id
.id), str(istate
)))
424 inv
= mline
.account_invoice_line
.invoice_id
425 for payment
in inv
.payment_ids
:
426 if payment
.invoice
.type == 'out_refund':
429 elif istate
== 'open' and s
!= 0:
431 elif istate
== 'cancel' and s
!= 0 and s
!= 1:
433 elif (istate
== 'draft' or istate
== 'proforma') and s
!= 0 and s
!= 1:
435 elif mline
.pos_order_line
and mline
.pos_order_line
.order_id
:
436 ostate
= mline
.pos_order_line
.order_id
.state
437 print("DEV: [pos_membership] [Partner] [_membership_state] [pos_order_line]: id=%s ostate=%s" % (str(mline
.pos_order_line
.order_id
.id), str(ostate
)))
438 if ostate
== 'paid' and s
!= 0 and s
!= 1:
440 if ostate
== 'invoiced':
444 # XXX: regarder l'équivalent de out_refund pour un pos.order
445 print("DEV: [pos_membership] [partner] [_membership_state]: paid: TODO")
446 #inv = mline.pos_order_line.order_id
447 #for payment in inv.payment_ids:
448 # if payment.invoice.type == 'out_refund':
451 elif ostate
== 'open' and s
!= 0:
452 # XXX: 1 donne invoiced, c'est pitet pas bon
453 print("DEV: [pos_membership] [partner] [_membership_state]: invoiced: TODO")
455 elif ostate
== 'cancel' and s
!= 0 and s
!= 1:
457 elif ostate
== 'draft' and s
!= 0 and s
!= 1:
460 for mline
in partner_data
.member_lines
:
461 if mline
.date_from
< today
and \
462 mline
.date_to
< today
and \
463 mline
.date_from
<= mline
.date_to
and \
464 ((mline
.account_invoice_line
and mline
.account_invoice_line
.invoice_id
.state
) == 'paid' or \
465 (mline
.pos_order_line
and \
466 (mline
.pos_order_line
.order_id
.state
== 'paid' or \
467 mline
.pos_order_line
.order_id
.state
== 'done' or \
468 mline
.pos_order_line
.order_id
.state
== 'invoiced' ))):
484 if partner_data
.free_member
and s
!= 0:
486 if partner_data
.associate_member
:
487 res_state
= self
._membership
_state
(cr
, uid
, [partner_data
.associate_member
.id], name
, args
, context
=context
)
488 res
[id] = res_state
[partner_data
.associate_member
.id]
489 print("DEV: [pos_membership] [Partner] [_membership_state]: res=%s" % (str(res
)))
492 def _membership_date(self
, cr
, uid
, ids
, name
, args
, context
=None):
493 """Return date of membership"""
496 member_line_obj
= self
.pool
.get('membership.membership_line')
497 print("DEV: [pos_membership] [Partner] [_membership_date]: ids=%s" % (str(ids
)))
498 for partner
in self
.browse(cr
, uid
, ids
, context
=context
):
499 if partner
.associate_member
:
500 partner_id
= partner
.associate_member
.id
502 partner_id
= partner
.id
504 'membership_start': False,
505 'membership_stop': False,
506 'membership_cancel': False
508 if name
== 'membership_start':
509 line_id
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
510 limit
=1, order
='date_from', context
=context
)
512 res
[partner
.id]['membership_start'] = member_line_obj
.read(cr
, uid
, line_id
[0],
513 ['date_from'], context
=context
)['date_from']
514 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_start]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_start'])))
516 if name
== 'membership_stop':
517 line_id1
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner_id
),('date_cancel','=',False)],
518 limit
=1, order
='date_to desc', context
=context
)
520 res
[partner
.id]['membership_stop'] = member_line_obj
.read(cr
, uid
, line_id1
[0],
521 ['date_to'], context
=context
)['date_to']
522 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_stop]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_stop'])))
524 if name
== 'membership_cancel':
525 if partner
.membership_state
== 'canceled':
526 line_id2
= member_line_obj
.search(cr
, uid
, [('partner', '=', partner
.id)], limit
=1, order
='date_cancel', context
=context
)
528 res
[partner
.id]['membership_cancel'] = member_line_obj
.read(cr
, uid
, line_id2
[0], ['date_cancel'], context
=context
)['date_cancel']
529 print("DEV: [pos_membership] [Partner] [_membership_date] [membership_cancel]: ids=%s date=%s" % (str(ids
), str(res
[partner
.id]['membership_cancel'])))
530 print("DEV: [pos_membership] [Partner] [_membership_date]: res=%s" % (str(res
)))
533 def _get_partners(self
, cr
, uid
, ids
, context
=None):
536 ids2
= self
.search(cr
, uid
, [('associate_member', 'in', ids2
)], context
=context
)
540 def __get_membership_state(self
, *args
, **kwargs
):
541 return self
._membership
_state
(*args
, **kwargs
)
544 'membership_state': fields
.function(
545 __get_membership_state
,
546 string
= 'Current Membership Status', type = 'selection',
549 # NOTE: il est important que la priorité soit plus grande
550 # que les membership_{start,stop,cancel}
551 # car _membership_state s'en sert et doit donc les trouver à jour.
552 'account.invoice': (_get_invoice_partner
, ['state'], 20),
553 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 20),
554 'membership.membership_line': (_get_partner_id
, ['state'], 20),
555 'res.partner': (_get_partners
, ['free_member', 'membership_state', 'associate_member'], 20)
556 }, help="""It indicates the membership state.
557 -Non Member: A partner who has not applied for any membership.
558 -Cancelled Member: A member who has cancelled his membership.
559 -Old Member: A member whose membership date has expired.
560 -Waiting Member: A member who has applied for the membership and whose invoice is going to be created.
561 -Invoiced Member: A member whose invoice has been created.
562 -Paying member: A member who has paid the membership fee."""),
563 'membership_start': fields
.function(
564 _membership_date
, multi
= 'membership_start',
565 string
= 'Membership Start Date', type = 'date',
567 'account.invoice': (_get_invoice_partner
, ['state'], 10),
568 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
569 'membership.membership_line': (_get_partner_id
, ['state'], 10),
570 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
571 }, help="Date from which membership becomes active."),
572 'membership_stop': fields
.function(
574 string
= 'Membership End Date', type='date', multi
='membership_stop',
576 'account.invoice': (_get_invoice_partner
, ['state'], 10),
577 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 10),
578 'membership.membership_line': (_get_partner_id
, ['state'], 10),
579 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
580 }, help="Date until which membership remains active."),
581 'membership_cancel': fields
.function(
583 string
= 'Cancel Membership Date', type='date', multi
='membership_cancel',
585 'account.invoice': (_get_invoice_partner
, ['state'], 11),
586 'pos.order': (_get_order_partner
, ['state', 'partner_id'], 11),
587 'membership.membership_line': (_get_partner_id
, ['state'], 10),
588 'res.partner': (lambda self
, cr
, uid
, ids
, c
={}: ids
, ['free_member'], 10)
589 }, help="Date on which membership has been cancelled"),
594 class pos_order(osv
.osv
):
595 _inherit
= 'pos.order'
597 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py
598 def action_invoice(self
, cr
, uid
, ids
, context
=None):
599 print ("DEV: [pos_membership] [pos_order] [action_invoice]")
600 wf_service
= netsvc
.LocalService("workflow")
601 inv_ref
= self
.pool
.get('account.invoice')
602 inv_line_ref
= self
.pool
.get('account.invoice.line')
603 product_obj
= self
.pool
.get('product.product')
606 for order
in self
.pool
.get('pos.order').browse(cr
, uid
, ids
, context
=context
):
608 inv_ids
.append(order
.invoice_id
.id)
611 if not order
.partner_id
:
612 raise osv
.except_osv(_('Error!'), _('Please provide a partner for the sale.'))
614 acc
= order
.partner_id
.property_account_receivable
.id
615 # XXX: copied from openerp/addons/point_of_sale/point_of_sale.py to fix account.invoice.line creation
618 'origin': order
.name
,
620 'journal_id': order
.sale_journal
.id or None,
621 'type': 'out_invoice',
622 'reference': order
.name
,
623 'partner_id': order
.partner_id
.id,
624 'comment': order
.note
or '',
625 'currency_id': order
.pricelist_id
.currency_id
.id, # considering partner's sale pricelist's currency
628 inv
.update(inv_ref
.onchange_partner_id(cr
, uid
, [], 'out_invoice', order
.partner_id
.id)['value'])
629 if not inv
.get('account_id', None):
630 inv
['account_id'] = acc
631 for line
in order
.lines
:
633 #'invoice_id': inv_id,
634 'product_id': line
.product_id
.id,
635 'quantity': line
.qty
,
637 inv_name
= product_obj
.name_get(cr
, uid
, [line
.product_id
.id], context
=context
)[0][1]
638 inv_line
.update(inv_line_ref
.product_id_change(cr
, uid
, [],
640 line
.product_id
.uom_id
.id,
641 line
.qty
, partner_id
= order
.partner_id
.id,
642 fposition_id
=order
.partner_id
.property_account_position
.id)['value'])
643 if line
.product_id
.description_sale
:
644 inv_line
['note'] = line
.product_id
.description_sale
645 inv_line
['price_unit'] = line
.price_unit
646 inv_line
['discount'] = line
.discount
647 inv_line
['name'] = inv_name
648 inv_line
['invoice_line_tax_id'] = [(6, 0, [x
.id for x
in line
.product_id
.taxes_id
] )]
649 inv_line_ref
.create(cr
, uid
, inv_line
, context
=context
)
650 #inv_line_ref.create(cr, uid, inv_line, context=context)
651 inv
['invoice_line'].append((0, 0, inv_line
))
652 inv_id
= inv_ref
.create(cr
, uid
, inv
, context
=context
)
654 self
.write(cr
, uid
, [order
.id], {'invoice_id': inv_id
, 'state': 'invoiced'}, context
=context
)
655 inv_ref
.confirm_paid(cr
, uid
, [inv_id
], context
=context
)
656 inv_ids
.append(inv_id
)
657 inv_ref
.button_reset_taxes(cr
, uid
, [inv_id
], context
=context
)
658 wf_service
.trg_validate(uid
, 'pos.order', order
.id, 'invoice', cr
)
660 if not inv_ids
: return {}
662 mod_obj
= self
.pool
.get('ir.model.data')
663 res
= mod_obj
.get_object_reference(cr
, uid
, 'account', 'invoice_form')
664 res_id
= res
and res
[1] or False
666 'name': _('Customer Invoice'),
670 'res_model': 'account.invoice',
671 'context': "{'type':'out_invoice'}",
672 'type': 'ir.actions.act_window',
675 'res_id': inv_ids
and inv_ids
[0] or False,
678 def write(self
, cr
, uid
, ids
, vals
, context
=None):
679 print("DEV: [pos_membership] [pos_order] [write]: ids=%s vals=%s" % (str(ids
), str(vals
)))
680 pos_order_obj
= self
.pool
.get('pos.order')
681 res
= super(pos_order
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
682 print("DEV: [pos_membership] [pos_order] [write]: res=%s" % str(res
))
685 def create(self
, cr
, uid
, vals
, context
=None):
686 print("DEV: [pos_membership] [pos_order] [create]: vals=%s" % (str(vals
)))
687 pos_order_obj
= self
.pool
.get('pos.order')
688 res
= super(pos_order
, self
).create(cr
, uid
, vals
, context
=context
)
689 print("DEV: [pos_membership] [pos_order] [create]: res=%s" % (str(res
)))
694 class pos_order_line(osv
.osv
):
695 _inherit
= 'pos.order.line'
697 def write(self
, cr
, uid
, ids
, vals
, context
=None):
698 print("DEV: [pos_membership] [pos_order_line] [write]: ids=%s vals=%s context=%s" % (str(ids
), str(vals
), str(context
)))
699 member_line_obj
= self
.pool
.get('membership.membership_line')
700 res
= super(pos_order_line
, self
).write(cr
, uid
, ids
, vals
, context
=context
)
701 print ("DEV: [pos_membership] [pos_order_line] [write] [super] : res=%s" % str(res
))
702 for line
in self
.browse(cr
, uid
, ids
, context
=context
):
703 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
704 if line
.product_id
and line
.product_id
.membership
:
705 member_line_id
= member_line_obj
.search(cr
, uid
706 , [('partner', '=', line
.order_id
.partner_id
.id)
707 ,('pos_order_line', '=', line
.id)]
710 for member_line
in member_line_obj
.browse(cr
, uid
, member_line_id
, context
=context
):
711 # NOTE: get member_line created in pos_membership.pos_order_line.create
712 date_from
= member_line
.date_from
713 date_to
= member_line
.date_to
714 if line
.product_id
.membership_date2date
:
715 date_from
= ('date_from' in context
716 and context
.get('date_from')
717 and datetime
.strptime(context('date_from'), "%Y-%m-%d")
719 date_to
= date_from
+ relativedelta(months
= +12) # TODO: parameterize this delta?
720 date_from
= date_from
.strftime("%Y-%m-%d")
721 date_to
= date_to
.strftime("%Y-%m-%d")
722 print ("DEV: [pos_membership] [pos_order_line] [write] date_from: %s" % str(date_from
))
723 print ("DEV: [pos_membership] [pos_order_line] [write] date_to : %s" % str(date_to
))
724 member_line_obj
.write(cr
, uid
, member_line
.id
725 , {'date_from': date_from
729 if line
.product_id
.membership_grouped
:
730 if line
.order_id
.partner_id
.associate_members
:
731 associate_member_line_ids
= member_line_obj
.search(cr
, uid
732 , [ ('pos_order_line', '=', line
.id)
733 , ('partner', '!=', line
.order_id
.partner_id
.id)
736 for associate_member_line
in member_line_obj
.browse(cr
, uid
, associate_member_line_ids
, context
=context
):
737 print ("DEV: [pos_membership] [pos_order_line] [write] [associate] date_from: %s" % str(date_from
))
738 print ("DEV: [pos_membership] [pos_order_line] [write] [associate] date_to : %s" % str(date_to
))
739 member_line_obj
.write(cr
, uid
, associate_member_line
.id
740 , {'date_from': date_from
745 print("DEV: mettre une contrainte pour l'objet\
746 membership.membership_line interdisant les\
747 adhésions groupées reliées à des partenaires\
748 sans membres associés")
750 associate_member_line_ids
= member_line_obj
.search(cr
, uid
751 , [ ('pos_order_line', '=', line
.id)
752 , ('partner', '!=', line
.order_id
.partner_id
.id)
755 member_line_obj
.unlink(cr
, uid
, associate_member_line_ids
, context
=context
)
756 #Define member ident if it's necessary
757 partners
= [line
.order_id
.partner_id
]
758 if line
.order_id
.partner_id
.associate_members
:
759 partners
.extend(line
.order_id
.partner_id
.associate_members
)
761 if not i
.member_ident
:
762 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
763 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
764 if line
.product_id
and not line
.product_id
.membership
and ml_ids
:
765 # Product line has changed to a non membership product
766 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
767 print ("DEV: [pos_membership] [pos_order_line] [write] : return=%s" % str(res
))
770 def unlink(self
, cr
, uid
, ids
, context
=None):
771 """Remove Membership Line Record for Account Invoice Line
773 member_line_obj
= self
.pool
.get('membership.membership_line')
775 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', id)], context
=context
)
776 member_line_obj
.unlink(cr
, uid
, ml_ids
, context
=context
)
777 return super(pos_order_line
, self
).unlink(cr
, uid
, ids
, context
=context
)
779 def create(self
, cr
, uid
, vals
, context
=None):
780 member_line_obj
= self
.pool
.get('membership.membership_line')
781 print("DEV: [pos_membership] [pos_order_line] [create]: vals=%s context=%s" % (str(vals
), str(context
)))
782 res
= super(pos_order_line
, self
).create(cr
, uid
, vals
, context
=context
)
783 print ("DEV: [pos_membership] [pos_order_line] [create] [super] : res=%s" % str(res
))
784 line
= self
.browse(cr
, uid
, res
, context
=context
)
786 ml_ids
= member_line_obj
.search(cr
, uid
, [('pos_order_line', '=', line
.id)], context
=context
)
787 if line
.product_id
and line
.product_id
.membership
and not ml_ids
:
788 date_from
= line
.product_id
.membership_date_from
789 date_to
= line
.product_id
.membership_date_to
790 if line
.order_id
.date_order
> date_from
and line
.order_id
.date_order
< date_to
:
791 date_from
= line
.order_id
.date_order
792 if line
.product_id
.membership_date2date
:
793 date_from
= ('date_from' in context
794 and context
.get('date_from')
795 and datetime
.strptime(context
.get('date_from'), "%Y-%m-%d")
797 date_to
= date_from
+ relativedelta(days
= +364) # TODO: parameterize this delta?
798 date_from
= date_from
.strftime("%Y-%m-%d")
799 date_to
= date_to
.strftime("%Y-%m-%d")
800 print ("DEV: [pos_membership] [pos_order_line] [create] date_from: %s" % str(date_from
))
801 print ("DEV: [pos_membership] [pos_order_line] [create] date_to : %s" % str(date_to
))
802 member_line_obj
.create(cr
, uid
, {
803 'partner': line
.order_id
.partner_id
and line
.order_id
.partner_id
.id or False,
804 'membership_id': line
.product_id
.id,
805 'member_price': line
.price_unit
,
806 'date': time
.strftime('%Y-%m-%d'),
807 'date_from': date_from
,
809 'pos_order_line': line
.id,
811 partners
= [line
.order_id
.partner_id
]
812 if line
.product_id
.membership_grouped
and line
.order_id
.partner_id
.associate_members
:
813 partners
.extend(line
.order_id
.partner_id
.associate_members
)
814 #Adding membership lines just for associate partners
815 for associate_member
in line
.order_id
.partner_id
.associate_members
:
816 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_from: %s" % str(date_from
))
817 print ("DEV: [pos_membership] [pos_order_line] [create] [associate] date_to : %s" % str(date_to
))
818 member_line_obj
.create(cr
, uid
, {
819 'partner': associate_member
.id,
820 'membership_id': line
.product_id
.id,
821 'member_price': line
.price_unit
,
822 'date': time
.strftime('%Y-%m-%d'),
823 'date_from': date_from
,
825 'pos_order_line': line
.id,
827 elif line
.product_id
.membership_grouped
and not line
.order_id
.partner_id
.associate_members
:
828 raise osv
.except_osv(_('Error!!!'), _('You try to order grouped membership product to a partner who hasn\'t associated partners.'))
829 #Define member ident if it's necessary
832 print ("\033[7mXXX: [pos_membership] [pos_order_line] [create] : pos_order_line has no partner_id!\033[0m")
834 if not i
.member_ident
:
835 print ("DEV: [pos_membership] [pos_order_line] [create] [partners] : i=%s i.id=%s" % (str(i
), str(i
.id)))
836 mbr_id
= self
.pool
.get('ir.sequence').get(cr
, uid
, 'member_ident')
837 self
.pool
.get('res.partner').write(cr
, uid
, i
.id, {'member_ident': mbr_id
})
838 print ("DEV: [pos_membership] [pos_order_line] [create] : return=%s" % str(res
))
843 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: